Expanding upon the concept of a 3 key timed multisig, a 5 key timed multisig allows for multiple timelocks to be introduced for additional flexibility.
A timelock can be employed to allow a native 3 of 5 multisig to become 2 of 5, and eventually 1 of 5 for disaster recovery. This can be employed by using a miniscript tresh() with seven conditions:
timelock: after(int)1 or older(int) - either relative or absolute 2.
timelock: after(int) or older(int)3 - either relative or absolute 4.
pk(key1)6
pk(key2)7
pk(key3)8
pk(key4)9
pk(key5)10
The security of the descriptor template is not dependent on the value of a relative or absolute timelock, as it only impacts the duration of the timelock.
For reference transactions on testnet, short duration timelocks have been used. In practice timelock values will differ.
Relative timelock descriptors offer a structure that can persist across time, requiring a self-send to extend the timelock security, and thus offering a better ability to have standard timelock durations within templates.
It is harder to set established timelock values with absolute timelock descriptors as they need to be regularly updated.
older(32800) Halfway point of block height relative timelock11
older(65535) Maximum duration of a block height relative timelock12
older(4224680) Approximate Halfway point of epoch time relative timelock13
older(4259839) Maximum duration of an epoch time relative timelock14
Below is a reference diagram on how the 5 Key Time Layered Multisig operates across time:

wsh(thresh(3,pk(XPUB1),s:pk(XPUB2),s:pk(XPUB3),s:pk(XPUB4),s:pk(XPUB5),snu:older(100),snu:older(200)))
wsh(thresh(3,pk(XPUB1),s:pk(XPUB2),s:pk(XPUB3),s:pk(XPUB4),s:pk(XPUB5),snu:after(1694563200),snu:after(1694563200)))
wsh(thresh(3,pk(XPUB1),s:pk(XPUB2),s:pk(XPUB3),s:pk(XPUB4),s:pk(XPUB5),snu:after(1694563200),snu:after(1694476800)))
wsh(thresh(3,pk(XPUB1),s:pk(XPUB2),s:pk(XPUB3),s:pk(XPUB4),s:pk(XPUB5),snu:older(4194400),snu:older(4194500)))
(To Add Taproot descriptors once Minitapscript is merged into Core)
Bitcoin Script -->
after(n) =
NUM cannot be 0. ↩
older(n) =
Key expressions (K Type) take their inputs from the top of the stack, but instead of verifying a condition directly they always push a public key onto the stack, for which a signature is still required to satisfy the expression. A "K" can be converted into a "B" using the c: wrapper (CHECKSIG). ↩
pk(key1) = c:pk_k(key1) --> <key1> CHECKSIG ↩
pk(key2) = c:pk_k(key2) --> <key2> CHECKSIG ↩
pk(key3) = c:pk_k(key3) --> <key3> CHECKSIG ↩
pk(key4) = c:pk_k(key4) --> <key4> CHECKSIG ↩
pk(key5) = c:pk_k(key5) --> <key5> CHECKSIG ↩
~278 days assuming constant hashrate ↩
~455 days assuming constant hashrate ↩
~180 days 6 months ↩
~388 days ↩
after(int), older(int): Require that the nLockTime or nSequence value is at least (int). ↩
after(int), older(int): Require that the nLockTime or nSequence value is at least (int). ↩